package com.example.kotlincoroutine

import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.supervisorScope
import org.junit.Test
import java.lang.IllegalArgumentException
import kotlin.system.measureTimeMillis

class CoroutineTest01 {

    //把函数变成协程到方式用runBlocking
    @Test
    fun `test coroutine builder`() = runBlocking {
        //协程构建器：返回Job
        val job1 = launch {
            delay(200)
            println("job1 finished.")
        }
        //协程构建器:返回Deferred,也是一个Job，可以使用await()在一个延期到值上得到它到结果
        val job2 = async {
            delay(200)
            println("job2 finished.")
            "job2 result"
        }
        println("adafd--" + job2.await())
    }

    @Test
    fun `test coroutine join`() = runBlocking {
        //协程构建器：返回Job
        val job1 = launch {
            delay(2000)
            println("one finished.")
        }
        job1.join() //用了这个就会优先执行
        //协程构建器:返回Deferred,也是一个Job，可以使用await()在一个延期到值上得到它到结果
        val job2 = launch {
            delay(200)
            println("two finished.")
        }

        val job3 = launch {
            delay(200)
            println("three finished.")
        }

    }

    @Test
    fun `test coroutine await`() = runBlocking {
        //协程构建器：返回Job
        val job1 = async {
            delay(2000)
            println("one finished.")
        }
        job1.await() //用了这个就会等待执行后才执行后面的代码
        //协程构建器:返回Deferred,也是一个Job，可以使用await()在一个延期到值上得到它到结果
        val job2 = async {
            delay(200)
            println("two finished.")
        }

        val job3 = async {
            delay(200)
            println("three finished.")
        }

    }

    @Test
    fun `test sync`() = runBlocking {
        //下面为同步：执行大概2S
        val time = measureTimeMillis {
            val one = doOne()
            val two = doTwo()
            println(one + two)
        }
        println("time=$time")
    }

    @Test
    fun `test combine async`() = runBlocking {
        //下面为同步：执行大概1S
        val time = measureTimeMillis {
            val one = async { doOne() }
            val two = async { doTwo() }
//            println(one.await() + two.await())
        }
        println("time=$time")
    }

    @Test
    fun `test combine launch`() = runBlocking {
        //下面为同步：执行大概1S
        val time = measureTimeMillis {
            val one = launch { doOne() }
            val two = launch { doTwo() }
            println("没有返回值")
//            println("没有返回值"+one.join()+two.join())
        }
        println("time=$time")
    }

    private suspend fun doOne(): Int {
        delay(1000)
        println("14")
        return 14
    }

    private suspend fun doTwo(): Int {
        delay(1000)
        println("15")
        return 15
    }

    @Test
    fun `test start mode`() = runBlocking {
        //协程的启动模式：DEFAULT，LAZY，ATOMIC，UNDISPATCHED
        //DEFAULT 当被调度时，立即调度（并没有马上执行），没有执行之前可以随时被取消，取消也是响应状态，并不会马上取消
        //ATOMIC 当被调度时，立即调度（并没有马上执行），当没有执行到第一个挂起点（suspend函数）时，之前的代码都会执行，否则后面的代码会响应取消状态
        //LAZY 需要手动指定才能执行，如join，start，await调用时，才会开始调度，如果调度前被取消，会抛出异常
        //UNDISPATCHED 立即在当前函数调用栈中执行，直到遇到第一个挂起点（也就是说遇到第一个挂起点后，之后的线程就会发生改变）
        //协程是基于线程的，runBlocking（在主线程）会等待所有的子协程完成后输出
//        val job = launch(start = CoroutineStart.DEFAULT) {
//            //子协程挂起
//            try {
//                delay(10000)
//                println("Job finished.")
//            } catch (e: Exception) {
//                println("异常：" + e.message)
//            }
//        }
//        //主协程挂起
//        delay(1000)
//        //把子协程取消了
//        job.cancel()
//        val job = async (start = CoroutineStart.LAZY) {
//
//        }
//        job.await()
        val job = async(context = Dispatchers.IO, start = CoroutineStart.UNDISPATCHED) {
            println(Thread.currentThread().name)//在主线程
            delay(1000)
            println(Thread.currentThread().name)//在子协程
        }
    }

    @Test
    fun `test coroutine scope builder`() = runBlocking {
        coroutineScope {//一个协程失败，其他都取消
            //协程构建器：返回Job
            val job1 = launch {
                delay(400)
                println("job1 finished.")
            }
            //协程构建器:返回Deferred,也是一个Job，可以使用await()在一个延期到值上得到它到结果
            val job2 = async {
                delay(200)
                println("job2 finished.")
                "job2 result"
                throw IllegalArgumentException("Custom Exception")
            }
        }
    }
    @Test
    fun `test supervisorScope scope builder`() = runBlocking {
        supervisorScope {//一个协程失败，其他不会影响
            //协程构建器：返回Job
            val job1 = launch {
                delay(400)
                println("job1 finished.")
            }
            //协程构建器:返回Deferred,也是一个Job，可以使用await()在一个延期到值上得到它到结果
            val job2 = async {
                delay(200)
                println("job2 finished.")
                "job2 result"
                throw IllegalArgumentException("Custom Exception")
            }
        }
    }
}